function PromiseRef(executor, allowRepeat) {
    let species = [];
    let onwaited;
    let onwait = function(w) {
        onwaited && onwaited(w);
    }
    let i = 0;
    let onresolve = function(data, first) {
        if (data && data.toString() == '[object Promise]' || data instanceof PromiseRef || data instanceof Promise) {
            data.then(onresolve, onreject)
        } else {
            if (first && allowRepeat) i = 0;
            let specie = species[i++];
            if (!specie) return;
            if (!specie.onfilfilled)
                return onresolve(data);
            try {
                onresolve(specie.onfilfilled(data));
            } catch (e) {
                onreject(e);
            }
        }
    }

    let onreject = function(e, first) {
        if (first && allowRepeat) i = 0;
        let specie = species[i++];
        if (!specie)
            return lasterror(e);
        if (!specie.onrejected)
            return onreject(e);
        try {
            onresolve(specie.onrejected(e));
        } catch (e) {
            onreject(e);
        }
    }

    function lasterror(e) {
        if (PromiseRef.lasterror) {
            PromiseRef.lasterror(e);
        } else {
            console.error(e)
        }
    }

    this.then = function(onfilfilled, onrejected) {
        if (typeof onfilfilled === 'function') {
            species.push({
                onfilfilled
            });
        }
        if (typeof onrejected === 'function') {
            species.push({
                onrejected
            });
        }
        return this;
    }
    this.catch = function(onrejected) {
        if (typeof onrejected === 'function') {
            species.push({
                onrejected
            });
        }
        return this;
    }
    this.wait = function(onwait) {
        return onwaited = onwait, this;
    }
    setTimeout(() => {
        executor(r => onresolve(r, true), e => onreject(e, true), onwait);
    })
}
PromiseRef.prototype.finally = function(onfilfilled) {
    return this.then(r => (onfilfilled(r), r), r => (onfilfilled(r), Promise.reject(r)))
}
PromiseRef.reject = function(e) {
    return new PromiseRef(function(resolve, reject) {
        reject(e)
    })
}
PromiseRef.resolve = function(r) {
    return new PromiseRef(function(resolve, reject) {
        resolve(r)
    })
}
window.PromiseRef = PromiseRef;